/* ================================================= */
/* parser pour l'analyse syntaxique d'un fichier BPO */
/* author Mathieu Barbin                             */
/* version 1.0.*                                     */
/* ================================================= */

%{
  open Message
  open Inputtools
%}
%token DEFINE
%token SYSARGV
%token STRINGARGV
%token TOK_PIPE
%token METHOD
%token MAIN
%token SOURCE
%token INIT
%token TEST
%token WITH
%token ROM
%token RAM
%token WORD_CODE
%token TEXT
%token FILE
%token BINARYFILE
%token LEX_LOG
%token LEX_MOD
%token LEX_MIN
%token LEX_MAX
%token LEX_ADD
%token LEX_SUB
%token LEX_MULT
%token LEX_DIV
%token LEX_EXP
%token LPAREN
%token RPAREN
%token EGAL
%token POINTPOINT
%token POINT_INTER
%token VIRG
%token DEUX_POINTS
%token LCROCHET
%token RCROCHET
%token LACC
%token RACC
%token <int> INT
%token <string> IDENT
%token <string> STRING
%token <string> CODE
%token <string> CODE01
%token EOF

// le fichier meta bpo comprend :
// 1 - #source = le langage utilise pour le test (default : "ocaml")
// 2 - #define (facultatif)
// 3 - Des declarations de memoires Ram et Rom (facultatif)
// 4 - #init (facultatif) 
// 5 - #method blabla + #main interface #with code blabla ...

%type < (string * (Inputtools.macro_BP list) * (Inputtools.declaration_memoire list) * (int * string) * Inputtools.bpo_object) >input 
%start input

%%

input: 
  | source_declaration macro_define_list declaration_memoire_list init_possible bpo_object
    { ($1, $2, $3, $4, $5) }
;

source_declaration:
  | SOURCE EGAL STRING { $3 }
  |                    { "ocaml" }
;

init_possible:
  |            { (!index_ligne_bpo_file, "") }
  | INIT CODE  { (!index_ligne_bpo_file, $2) }
;

code_source:
  | WITH WORD_CODE CODE { (!index_ligne_bpo_file, $3) }
;

macro_define_list:
  |   { [] }
  | DEFINE IDENT expr_arith macro_define_list                        
      {  (MacDefine 
	    {
	      fichier_macro = message#get_bpo_file;
	      ligne_macro = !index_ligne_bpo_file; 
	      nom_macro = $2; 
	      corps_macro = DefInt $3
	    })::($4) 
      }
  | DEFINE IDENT STRING macro_define_list                        
      { (MacDefine 
	   {
	     fichier_macro = message#get_bpo_file;
	     ligne_macro = !index_ligne_bpo_file; 
	     nom_macro = $2; 
	     corps_macro = DefString $3
	   })::($4) 
      } 
  | SYSARGV IDENT macro_define_list
      { (MacIntArg (!index_ligne_bpo_file, $2))::($3)
      }
  | STRINGARGV IDENT macro_define_list
      { (MacStringArg (!index_ligne_bpo_file, $2))::($3)
      }
;

declaration_memoire_list:
  |                                            { [] }
  | une_memoire declaration_memoire_list       { $1::$2 } 
;

une_memoire:
  | ROM IDENT LPAREN expr_arith VIRG expr_arith RPAREN EGAL text_or_file           
      { 
	{ 
	  fichier_dcl_m = message#get_bpo_file;
	  ligne_dcl_m = !index_ligne_bpo_file;
	  type_dcl_m = ROM_decl $2;
	  arite_entree_dcl_m = $4;
	  arite_sortie_dcl_m = $6;
	  description_entree_dcl_m = Some $9 
	}
      }

  | RAM IDENT LPAREN expr_arith VIRG expr_arith RPAREN EGAL text_or_file           
      { 
	{ 
	  fichier_dcl_m = message#get_bpo_file;
	  ligne_dcl_m = !index_ligne_bpo_file;
	  type_dcl_m = RAM_decl $2;
	  arite_entree_dcl_m = $4;
	  arite_sortie_dcl_m = $6;
	  description_entree_dcl_m = Some $9 
	}
      }

  | RAM IDENT LPAREN expr_arith VIRG expr_arith RPAREN                             
      { 
	{
	  fichier_dcl_m = message#get_bpo_file;
	  ligne_dcl_m = !index_ligne_bpo_file;
	  type_dcl_m = RAM_decl $2;
	  arite_entree_dcl_m = $4;
	  arite_sortie_dcl_m = $6;
	  description_entree_dcl_m = None 
	} 
      }
;

text_or_file:  
  | TEXT CODE01                                                      { Text $2 }
  | FILE LPAREN STRING RPAREN                                        { File $3 }
  | BINARYFILE LPAREN STRING RPAREN				     { BinaryFile $3 }	
;

bpo_object:
  | bpo_method_list bpo_main  
      { 
	{
	  bpo_methods = $1;
	  bpo_main = $2
	}
      }
;

bpo_method_list:
  |                            { [] }
  | bpo_method bpo_method_list { $1::$2 }
;

bpo_interface:
  | variables_list EGAL bpo_output_net_vars
      {
	{
	  bpo_line = !index_ligne_bpo_file;
	  bpo_input = BPOInputNetVars $1;
	  bpo_output = $3
	}
      }
  | ident_indexation_variable_parenthese_option EGAL bpo_output_net_vars
      {
	{ 
	  bpo_line = !index_ligne_bpo_file;
	  bpo_input = BPOVarArg $1;
	  bpo_output = $3
	}
      }
;

bpo_output_net_vars :
  | variables_list { BPOOutputNetVars $1 }
  | POINT_INTER    { UserSelf }
;

bpo_interface_avec_par:
  | LPAREN arguments RPAREN EGAL bpo_output_net_vars
      {
        {
          bpo_line = !index_ligne_bpo_file;
	  bpo_input = BPOInputNetVars $2;
	  bpo_output = $5 
        }
      }
  | LPAREN ident_indexation_variable RPAREN EGAL bpo_output_net_vars
      {
        {
          bpo_line = !index_ligne_bpo_file;
	  bpo_input = BPOVarArg $2;
	  bpo_output = $5 
        }
      }
;



bpo_interface_avec_par_test:
  | LPAREN arguments RPAREN
      {
        {
          bpo_line = !index_ligne_bpo_file;
	  bpo_input = BPOInputNetVars $2;
	  bpo_output = BPOOutputNetVars []
        }
      }
  | LPAREN ident_indexation_variable RPAREN
      {
        {
          bpo_line = !index_ligne_bpo_file;
	  bpo_input = BPOVarArg $2;
	  bpo_output = BPOOutputNetVars []
        }
      }    
  | LPAREN arguments RPAREN EGAL variables_list
      {
        {
          bpo_line = !index_ligne_bpo_file;
	  bpo_input = BPOInputNetVars ($2@$5);
	  bpo_output = BPOOutputNetVars []
        }
      }
;

bpo_method:
  | string_args_name_list METHOD IDENT string_args_name_list bpo_interface code_source
      {
	{
	  bpo_attributs = $1;
	  bpo_name = $3;
	  bpo_string_args_name = Asked $4;
	  bpo_interface = $5;
	  bpo_source = $6
	}
      }
;

bpo_main:
  | main_string_args_name_list TOK_PIPE string_args_name_list bpo_interface_avec_par code_source
      {
	{
	  bpo_attributs = $1;
	  bpo_name = "pipe";
	  bpo_string_args_name = Asked $3;
	  bpo_interface = $4;
	  bpo_source = $5
	}
      }

  | main_string_args_name_list TOK_PIPE IDENT string_args_name_list bpo_interface_avec_par code_source
      {
	{
	  bpo_attributs = $1;
	  bpo_name = $3;
	  bpo_string_args_name = Asked $4;
	  bpo_interface = $5;
	  bpo_source = $6
	}
      }

  | main_string_args_name_list MAIN string_args_name_list bpo_interface code_source
      {
	{
	  bpo_attributs = $1;
	  bpo_name = "main";
	  bpo_string_args_name = Asked $3;
	  bpo_interface = $4;
	  bpo_source = $5
	}
      }

  | main_string_args_name_list TEST string_args_name_list bpo_interface_avec_par_test code_source
      {
	{
	  bpo_attributs = $1;
	  bpo_name = "test";
	  bpo_string_args_name = Asked $3;
	  bpo_interface = $4;
	  bpo_source = $5
	}
      }

  | main_string_args_name_list TEST IDENT string_args_name_list bpo_interface_avec_par_test code_source
      {
	{
	  bpo_attributs = $1;
	  bpo_name = $3;
	  bpo_string_args_name = Asked $4;
	  bpo_interface = $5;
	  bpo_source = $6
	}
      }

;

string_args_name_list :
  |  { [] }
  | LCROCHET simple_ident_list RCROCHET { $2 }
;

main_string_args_name_list :
  |  { [] }
  | LPAREN simple_ident_list RPAREN { $2 }
;


simple_ident_list :
  | IDENT { [$1] }
  | IDENT VIRG simple_ident_list { $1::$3 }
;

variables_list:
    LPAREN arguments RPAREN                            { $2 }
  | arguments                                          { $1 }
; 

arguments:
  |                                                    { [] }
  | argument                                           { [$1] }
  | argument VIRG arguments                            { $1::$3 }
;
 
argument:
  | IDENT                                              { Simple $1 }
  | IDENT indexation_list                              { Vecteur (!index_ligne_bpo_file,
								  $1,$2) }
;

indexation_list:
  | indexation                                         { [$1] }
  | indexation indexation_list                         { $1::$2 }
;

indexation:
  | DEUX_POINTS LCROCHET expr_arith RCROCHET           { SegmentInit $3 }
  | LCROCHET expr_arith POINTPOINT expr_arith RCROCHET { Intervalle ($2, $4) }
  | LCROCHET expr_arith RCROCHET                       { Index $2 }
;

ident_indexation_variable:
  | IDENT DEUX_POINTS LCROCHET POINT_INTER RCROCHET           { $1 }
  | IDENT LCROCHET expr_arith POINTPOINT POINT_INTER RCROCHET { $1 }
;

ident_indexation_variable_parenthese_option:
  | LPAREN ident_indexation_variable RPAREN { $2 }
  | ident_indexation_variable               { $1 }
;
 
// LES EXPRESSIONS ARITHMETIQUES 

expr_arith:
  | expr_arith LEX_ADD expr_arith_close    { ADD ($1, $3) }
  | expr_arith LEX_SUB expr_arith_close    { SUB ($1, $3) }
  | LEX_SUB expr_arith_close               { SUB (CST 0, $2) }
  | expr_arith_close                       { $1 }
;

expr_arith_close:
  | expr_arith_close LEX_DIV expr_prio     { DIV ($1, $3) }
  | expr_arith_close LEX_MULT expr_prio    { MULT ($1, $3) }
  | expr_arith_close LEX_MOD expr_prio     { MOD ($1, $3) }
  | expr_prio                              { $1 }
;

expr_prio:
  | expr_prio LEX_EXP expr_terminale       { EXP ($1, $3) }
  | LEX_LOG expr_terminale                 { LOG $2 }
  | expr_terminale                         { $1 }
                               
expr_terminale:
  | INT                                                  { CST $1 }
  | IDENT                                                { VAR $1 }
  | LPAREN expr_arith RPAREN                             { $2 }
  | LEX_MAX LPAREN expr_arith VIRG expr_arith RPAREN     { MAX ($3, $5) }
  | LEX_MIN LPAREN expr_arith VIRG expr_arith RPAREN     { MIN ($3, $5) } 
;
